package com.miaoshaoproject.controller;

import com.google.common.util.concurrent.RateLimiter;
import com.miaoshaoproject.error.BussinessException;
import com.miaoshaoproject.error.EmBussinessError;
import com.miaoshaoproject.mq.MqProducer;
import com.miaoshaoproject.service.ItemService;
import com.miaoshaoproject.service.PromoService;
import com.miaoshaoproject.service.model.OrderModel;
import com.miaoshaoproject.service.model.UserModel;
import com.miaoshaoproject.response.CommonReturnType;
import com.miaoshaoproject.service.OrderService;
import com.miaoshaoproject.utils.CodeUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.*;

@Controller("order")
@RequestMapping("/order")
@CrossOrigin(allowCredentials = "true",allowedHeaders = "*")
public class OrderController extends BaseController {
    @Autowired
    private OrderService orderService;
    @Autowired
    private HttpServletRequest httpServletRequest;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private MqProducer mqProducer;
    @Autowired
    private ItemService itemService;
    @Autowired
    private PromoService promoService;

    public ExecutorService executorService;

    private RateLimiter orderCreateRateLimiter;

    @PostConstruct
    public void init(){
        executorService=Executors.newFixedThreadPool(20);
        orderCreateRateLimiter=RateLimiter.create(300);
    }


    //生成验证码
    @RequestMapping(value = "/generateverifycode",method = {RequestMethod.POST,RequestMethod.GET})
    @ResponseBody
    public void generateverifycode(HttpServletResponse response) throws BussinessException, IOException {
        //获取用户的登录信息
        String token = httpServletRequest.getParameterMap().get("token")[0];
        if(StringUtils.isEmpty(token)){
            throw new BussinessException(EmBussinessError.USER_NOT_LOGIN,"用户还未登陆，不能生成验证码");
        }
        UserModel userModel=(UserModel)redisTemplate.opsForValue().get(token);
        if(userModel==null){
            throw new BussinessException(EmBussinessError.USER_NOT_LOGIN,"用户还未登陆，不能生成验证码");
        }
        Map<String,Object> map=CodeUtil.generateCodeAndPic();
        redisTemplate.opsForValue().set("verify_code_"+userModel.getId(),map.get("code"));
        redisTemplate.expire("verify_code_"+userModel.getId(),10,TimeUnit.MINUTES);
        ImageIO.write((RenderedImage)map.get("codePic"),"jpeg",response.getOutputStream());
    }


    //生成秒杀令牌
    @RequestMapping(value = "/generatetoken",method = {RequestMethod.POST},consumes = {CONTENT_TYPE_FORMED})
    @ResponseBody
    public CommonReturnType generatetoken(@RequestParam(name="itemId") Integer itemId,
                                        @RequestParam(name="promoId") Integer promoId,
                                        @RequestParam(name="vertifyCode") String vertifyCode) throws BussinessException {
        //获取用户的登录信息
        String token = httpServletRequest.getParameterMap().get("token")[0];
        if(StringUtils.isEmpty(token)){
            throw new BussinessException(EmBussinessError.USER_NOT_LOGIN,"用户还未登陆，不能下单");
        }
        UserModel userModel=(UserModel)redisTemplate.opsForValue().get(token);
        if(userModel==null){
            throw new BussinessException(EmBussinessError.USER_NOT_LOGIN,"用户还未登陆，不能下单");
        }

        //通过verifycode验证验证码的有效性
        String redisVerifyCode= (String) redisTemplate.opsForValue().get("verify_code_"+userModel.getId());
        if(StringUtils.isEmpty(redisVerifyCode)){
            throw new BussinessException(EmBussinessError.PARAMETER_VALIDATION_ERROR,"请求非法");
        }
        if (!redisVerifyCode.equalsIgnoreCase(vertifyCode)){
            throw new BussinessException(EmBussinessError.PARAMETER_VALIDATION_ERROR,"请求非法,验证码错误");
        }
        //获取秒杀访问令牌
        String promoToken=promoService.generateSecondKillToken(promoId,itemId,userModel.getId());
        if (promoToken==null){
            throw new BussinessException(EmBussinessError.PARAMETER_VALIDATION_ERROR,"生成令牌失败");
        }
        return CommonReturnType.create(promoToken);
    }
    //封装下单请求
    @RequestMapping(value = "/createorder",method = {RequestMethod.POST},consumes = {CONTENT_TYPE_FORMED})
    @ResponseBody
    public CommonReturnType createOrder(@RequestParam(name="itemId") Integer itemId,
                                        @RequestParam(name="promoId",required = false) Integer promoId,
                                        @RequestParam(name="amount") Integer amount,
                                        @RequestParam(name="promoToken",required = false) String promoToken) throws BussinessException {
        //判断是否登录 Boolean isLogin=(Boolean) httpServletRequest.getSession().getAttribute("IS_LOGIN");
        /*if(isLogin==null||!isLogin.booleanValue()){
            throw new BussinessException(EmBussinessError.USER_NOT_LOGIN);
        }*/
        //UserModel userModel=(UserModel)httpServletRequest.getSession().getAttribute("LOGIN_USER");

        //限流代码
        if(orderCreateRateLimiter.tryAcquire()){
            throw new BussinessException(EmBussinessError.RATELIMIT);
        }

        //获取用户的登录信息
        String token = httpServletRequest.getParameterMap().get("token")[0];
        if(StringUtils.isEmpty(token)){
            throw new BussinessException(EmBussinessError.USER_NOT_LOGIN,"用户还未登陆，不能下单");
        }
        UserModel userModel=(UserModel)redisTemplate.opsForValue().get(token);
        if(userModel==null){
            throw new BussinessException(EmBussinessError.USER_NOT_LOGIN,"用户还未登陆，不能下单");
        }

        //校验秒杀令牌是否正确

        if (promoId!=null){
            String inRedisPromoToken=redisTemplate.opsForValue().get("promo_token_"+promoId+"_userId_"+userModel.getId()+"_itemId_"+itemId).toString();
            if (inRedisPromoToken==null){
                throw new BussinessException(EmBussinessError.PARAMETER_VALIDATION_ERROR,"秒杀令牌校验失败");
            }
            if(!StringUtils.equals(promoToken,inRedisPromoToken)){
                throw new BussinessException(EmBussinessError.PARAMETER_VALIDATION_ERROR,"秒杀令牌校验失败");
            }

        }


        //OrderModel orderModel=orderService.createOrder(userModel.getId(),itemId,promoId,amount);
        //判断库存是否已售罄，若售罄key存在，直接下单失败
        if (redisTemplate.hasKey("promo_item_stock_invalid_"+itemId)){
            throw new BussinessException(EmBussinessError.STOCK_NOT_ENOUGH);
        }

        //同步调用线程池的submit方法
        //拥塞窗口为20的等待队列，用来队列化泄洪
        Future<Object> future= executorService.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                //加入存库流水init状态
                String stockLogId=itemService.initStockLog(itemId,amount);
                //再去完成对应的下单事务型消息
                if(!mqProducer.transactionAsyncReduceStock(userModel.getId(),itemId,promoId,amount,stockLogId)){
                    throw new BussinessException(EmBussinessError.UNKNOWN_ERROR,"下单失败");
                }
                return null;
            }
        });

        try {
            future.get();
        } catch (InterruptedException e) {
            throw  new BussinessException(EmBussinessError.UNKNOWN_ERROR);
        } catch (ExecutionException e) {
            throw  new BussinessException(EmBussinessError.UNKNOWN_ERROR);
        }

        return  CommonReturnType.create(null);
    }
}
